/*
 * File    : PluginInterfaceImpl.java
 * Created : 12 nov. 2003
 * By      : Olivier
 *
 * Azureus - a Java Bittorrent client
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details ( see the LICENSE file ).
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.gudy.azureus2.pluginsimpl.local;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.util.AEDiagnosticsEvidenceGenerator;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.DelayedEvent;
import org.gudy.azureus2.core3.util.FileUtil;
import org.gudy.azureus2.core3.util.IndentWriter;
import org.gudy.azureus2.core3.util.SystemProperties;
import org.gudy.azureus2.platform.PlatformManagerFactory;
import org.gudy.azureus2.plugins.Plugin;
import org.gudy.azureus2.plugins.PluginConfig;
import org.gudy.azureus2.plugins.PluginEvent;
import org.gudy.azureus2.plugins.PluginEventListener;
import org.gudy.azureus2.plugins.PluginException;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.PluginListener;
import org.gudy.azureus2.plugins.PluginManager;
import org.gudy.azureus2.plugins.PluginState;
import org.gudy.azureus2.plugins.clientid.ClientIDManager;
import org.gudy.azureus2.plugins.ddb.DistributedDatabase;
import org.gudy.azureus2.plugins.dht.mainline.MainlineDHTManager;
import org.gudy.azureus2.plugins.download.DownloadException;
import org.gudy.azureus2.plugins.download.DownloadManager;
import org.gudy.azureus2.plugins.ipfilter.IPFilter;
import org.gudy.azureus2.plugins.logging.Logger;
import org.gudy.azureus2.plugins.messaging.MessageManager;
import org.gudy.azureus2.plugins.network.ConnectionManager;
import org.gudy.azureus2.plugins.platform.PlatformManager;
import org.gudy.azureus2.plugins.sharing.ShareException;
import org.gudy.azureus2.plugins.sharing.ShareManager;
import org.gudy.azureus2.plugins.torrent.TorrentManager;
import org.gudy.azureus2.plugins.tracker.Tracker;
import org.gudy.azureus2.plugins.ui.UIManager;
import org.gudy.azureus2.plugins.ui.config.ConfigSection;
import org.gudy.azureus2.plugins.ui.config.Parameter;
import org.gudy.azureus2.plugins.ui.config.PluginConfigUIFactory;
import org.gudy.azureus2.plugins.update.UpdateManager;
import org.gudy.azureus2.plugins.utils.ShortCuts;
import org.gudy.azureus2.plugins.utils.Utilities;
import org.gudy.azureus2.pluginsimpl.local.clientid.ClientIDManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.ddb.DDBaseImpl;
import org.gudy.azureus2.pluginsimpl.local.deprecate.PluginDeprecation;
import org.gudy.azureus2.pluginsimpl.local.dht.mainline.MainlineDHTManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.download.DownloadManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.ipc.IPCInterfaceImpl;
import org.gudy.azureus2.pluginsimpl.local.ipfilter.IPFilterImpl;
import org.gudy.azureus2.pluginsimpl.local.logging.LoggerImpl;
import org.gudy.azureus2.pluginsimpl.local.messaging.MessageManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.network.ConnectionManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.sharing.ShareManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.torrent.TorrentManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.tracker.TrackerImpl;
import org.gudy.azureus2.pluginsimpl.local.ui.UIManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.ui.config.ConfigSectionHolder;
import org.gudy.azureus2.pluginsimpl.local.ui.config.ConfigSectionRepository;
import org.gudy.azureus2.pluginsimpl.local.ui.config.ParameterRepository;
import org.gudy.azureus2.pluginsimpl.local.ui.config.PluginConfigUIFactoryImpl;
import org.gudy.azureus2.pluginsimpl.local.update.UpdateManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.utils.ShortCutsImpl;
import org.gudy.azureus2.pluginsimpl.local.utils.UtilitiesImpl;

import com.aelitis.azureus.core.AzureusCoreComponent;
import com.aelitis.azureus.core.util.CopyOnWriteList;

/**
 * @author Olivier
 * 
 */
public final class PluginInterfaceImpl implements PluginInterface, AzureusCoreComponent {
    private static final LogIDs LOGID = org.gudy.azureus2.core3.logging.LogIDs.PLUGIN;

    private Plugin plugin;
    private PluginInitializer initialiser;
    private Object initialiser_key;
    protected ClassLoader class_loader;

    private CopyOnWriteList<PluginListener> listeners = new CopyOnWriteList<PluginListener>();
    private Set<PluginListener> init_complete_fired_set = new HashSet<PluginListener>();

    private CopyOnWriteList<PluginEventListener> event_listeners = new CopyOnWriteList<PluginEventListener>();
    private String key;
    private String pluginConfigKey;
    private Properties props;
    private String pluginDir;
    private PluginConfigImpl config;
    private String plugin_version;
    private Logger logger;
    private IPCInterfaceImpl ipc_interface;
    protected List children = new ArrayList();
    private PluginStateImpl state;

    /**
     * This is the plugin ID value we were given when we were created.
     * 
     * We might use it, but it depends what value is the plugins properties (which will override this value).
     */
    private String given_plugin_id;

    /**
     * We store this value as soon as someone calls getPluginID(), meaning we will return a consistent value for the plugin's lifetime.
     */
    private String plugin_id_to_use;

    protected PluginInterfaceImpl(Plugin _plugin, PluginInitializer _initialiser, Object _initialiser_key, ClassLoader _class_loader,
            List<File> _verified_files, String _key, Properties _props, String _pluginDir, String _plugin_id, String _plugin_version)

    throws PluginException {
        // check we're being created by the core

        StackTraceElement[] stack = Thread.currentThread().getStackTrace();

        int pos = 0;

        while (!stack[pos].getClassName().equals(PluginInterfaceImpl.class.getName())) {

            pos++;
        }

        String caller_class = stack[pos + 1].getClassName();

        if (!(caller_class.equals("org.gudy.azureus2.pluginsimpl.local.PluginInitializer") || caller_class
                .equals("org.gudy.azureus2.pluginsimpl.local.PluginInterfaceImpl"))) {

            throw (new PluginException("Invalid caller"));
        }

        // check we haven't been subclassed

        String class_name = getClass().getCanonicalName();

        if (class_name == null || !class_name.equals("org.gudy.azureus2.pluginsimpl.local.PluginInterfaceImpl")) {

            throw (new PluginException("Subclassing not permitted"));
        }

        plugin = _plugin;
        initialiser = _initialiser;
        initialiser_key = _initialiser_key;
        class_loader = _class_loader;
        key = _key;
        pluginConfigKey = "Plugin." + _key;
        props = new propertyWrapper(_props);
        pluginDir = _pluginDir;
        config = new PluginConfigImpl(this, pluginConfigKey);
        given_plugin_id = _plugin_id;
        plugin_version = _plugin_version;
        ipc_interface = new IPCInterfaceImpl(initialiser, plugin);
        state = new PluginStateImpl(this, initialiser);

        boolean verified = false;
        boolean bad = false;

        if (_plugin_id.endsWith("_v")) {

            if (plugin.getClass() == FailedPlugin.class) {

                verified = true;

            } else {
                if (_verified_files != null) {

                    File jar = FileUtil.getJarFileFromClass(plugin.getClass());

                    if (jar != null) {

                        for (File file : _verified_files) {

                            if (file.equals(jar)) {

                                verified = true;
                            }
                        }
                    }
                }
            }

            if (!verified) {

                bad = true;
            }
        }

        PluginInitializer.setVerified(this, plugin, verified, bad);
    }

    public Plugin getPlugin() {
        return (plugin);
    }

    public boolean isOperational() {
        PluginDeprecation.call("isOperational", this.given_plugin_id);
        return getPluginState().isOperational();
    }

    public Object getInitializerKey() {
        return (initialiser_key);
    }

    public PluginManager getPluginManager() {
        return (initialiser.getPluginManager());
    }

    public String getApplicationName() {
        return Constants.APP_NAME;
    }

    public String getAzureusName() {
        return (Constants.AZUREUS_NAME);
    }

    public String getAzureusVersion() {
        return (Constants.AZUREUS_VERSION);
    }

    public void addConfigSection(ConfigSection section) {
        // Method is used by autocat.
        ConfigSectionRepository.getInstance().addConfigSection(section, this);
    }

    public void removeConfigSection(ConfigSection section) {
        ConfigSectionRepository.getInstance().removeConfigSection(section);
    }

    public ConfigSection[] getConfigSections() {
        ArrayList<ConfigSection> list = ConfigSectionRepository.getInstance().getList();
        for (Iterator<ConfigSection> iter = list.iterator(); iter.hasNext();) {
            ConfigSection configSection = iter.next();
            if (configSection instanceof ConfigSectionHolder) {
                if (((ConfigSectionHolder) configSection).getPluginInterface() != this) {
                    iter.remove();
                }
            }
        }
        return list.toArray(new ConfigSection[0]);
    }

    /**
     * @deprecated
     */
    public void openTorrentFile(String fileName) {
        PluginDeprecation.call("openTorrentFile", this.getPluginID());
        try {
            getDownloadManager().addDownload(new File(fileName));
        } catch (DownloadException e) {
            throw (new RuntimeException(e));
        }
    }

    /**
     * @deprecated
     */
    public void openTorrentURL(String url) {
        PluginDeprecation.call("openTorrentURL", this.getPluginID());
        try {
            getDownloadManager().addDownload(new URL(url));
        } catch (Throwable e) {
            throw (new RuntimeException(e));
        }
    }

    public void setPluginName(String name) {
        props.put("plugin.name", name);
    }

    public String getPluginName() {
        String name = null;

        if (props != null) {

            name = (String) props.get("plugin.name");
        }

        if (name == null) {

            try {

                name = new File(pluginDir).getName();

            } catch (Throwable e) {

            }
        }

        if (name == null || name.length() == 0) {

            name = plugin.getClass().getName();
        }

        return (name);
    }

    public void setPluginVersion(String version) {
        props.put("plugin.version", version);
    }

    public String getPluginVersion() {
        String version = (String) props.get("plugin.version");

        if (version == null) {

            version = plugin_version;
        }

        return (version);
    }

    public String getPluginID() {
        String id = (String) props.get("plugin.id");

        // hack alert - azupdater needs to change its plugin id due to general hackage

        if (id != null && id.equals("azupdater")) {

            plugin_id_to_use = id;
        }

        if (plugin_id_to_use != null) {
            return plugin_id_to_use;
        }

        // Calculate what plugin ID value to use - look at the properties file
        // first, and if that isn't correct, base it on the given plugin ID
        // value we were given.

        if (id == null) {
            id = given_plugin_id;
        }
        if (id == null) {
            id = "<none>";
        }

        plugin_id_to_use = id;
        return plugin_id_to_use;
    }

    public boolean isMandatory() {
        PluginDeprecation.call("isMandatory", this.given_plugin_id);
        return getPluginState().isMandatory();
    }

    public boolean isBuiltIn() {
        PluginDeprecation.call("isBuiltIn", this.given_plugin_id);
        return getPluginState().isBuiltIn();
    }

    public Properties getPluginProperties() {
        return (props);
    }

    public String getPluginDirectoryName() {
        return pluginDir;
    }

    public String getPerUserPluginDirectoryName() {
        String name;
        if (pluginDir == null) {
            name = getPluginID();
        } else {
            name = new File(pluginDir).getName();
        }

        String str = new File(new File(SystemProperties.getUserPath(), "plugins"), name).getAbsolutePath();

        if (pluginDir == null) {

            return (str);
        }

        try {
            if (new File(pluginDir).getCanonicalPath().equals(new File(str).getCanonicalPath())) {

                return (pluginDir);
            }
        } catch (Throwable e) {

        }

        return (str);
    }

    public void setPluginDirectoryName(String name) {
        initialiser_key = new File(name);

        pluginDir = name;
    }

    public void addConfigUIParameters(Parameter[] parameters, String displayName) {
        ParameterRepository.getInstance().addPlugin(parameters, displayName);
    }

    public PluginConfig getPluginconfig() {
        return config;
    }

    public PluginConfigUIFactory getPluginConfigUIFactory() {
        return new PluginConfigUIFactoryImpl(config, pluginConfigKey);
    }

    public String getPluginConfigKey() {
        return (pluginConfigKey);
    }

    public Tracker getTracker() {
        return (TrackerImpl.getSingleton());
    }

    public ShareManager getShareManager()

    throws ShareException {
        return (ShareManagerImpl.getSingleton());
    }

    public DownloadManager getDownloadManager() {
        return (DownloadManagerImpl.getSingleton(initialiser.getAzureusCore()));
    }

    public MainlineDHTManager getMainlineDHTManager() {
        return new MainlineDHTManagerImpl(initialiser.getAzureusCore());
    }

    public TorrentManager getTorrentManager() {
        return (TorrentManagerImpl.getSingleton().specialise(this));
    }

    public Logger getLogger() {
        if (logger == null) {

            logger = new LoggerImpl(this);
        }

        return (logger);
    }

    public IPFilter getIPFilter() {
        return (new IPFilterImpl());
    }

    public Utilities getUtilities() {
        return (new UtilitiesImpl(initialiser.getAzureusCore(), this));
    }

    public ShortCuts getShortCuts() {
        return (new ShortCutsImpl(this));
    }

    public UIManager getUIManager() {
        return (new UIManagerImpl(this));
    }

    public UpdateManager getUpdateManager() {
        return (UpdateManagerImpl.getSingleton(initialiser.getAzureusCore()));
    }

    protected void unloadSupport() {
        ipc_interface.unload();

        UIManagerImpl.unload(this);
    }

    public boolean isUnloadable() {
        PluginDeprecation.call("unloadable", this.given_plugin_id);
        return getPluginState().isUnloadable();
    }

    public void reload() throws PluginException {
        PluginDeprecation.call("reload", this.given_plugin_id);
        getPluginState().reload();
    }

    public void unload() throws PluginException {
        PluginDeprecation.call("unload", this.given_plugin_id);
        getPluginState().unload();
    }

    public void uninstall() throws PluginException {
        PluginDeprecation.call("uninstall", this.given_plugin_id);
        getPluginState().uninstall();
    }

    public boolean isInitialisationThread() {
        return (initialiser.isInitialisationThread());
    }

    public ClientIDManager getClientIDManager() {
        return (ClientIDManagerImpl.getSingleton());
    }

    public ConnectionManager getConnectionManager() {
        return ConnectionManagerImpl.getSingleton(initialiser.getAzureusCore());
    }

    public MessageManager getMessageManager() {
        return MessageManagerImpl.getSingleton(initialiser.getAzureusCore());
    }

    public DistributedDatabase getDistributedDatabase() {
        return (DDBaseImpl.getSingleton(initialiser.getAzureusCore()));
    }

    public PlatformManager getPlatformManager() {
        return (PlatformManagerFactory.getPlatformManager());
    }

    protected void initialisationComplete() {
        Iterator<PluginListener> it = listeners.iterator();

        while (it.hasNext()) {

            try {
                fireInitComplete(it.next());

            } catch (Throwable e) {

                Debug.printStackTrace(e);
            }
        }

        for (int i = 0; i < children.size(); i++) {

            ((PluginInterfaceImpl) children.get(i)).initialisationComplete();
        }
    }

    protected void fireInitComplete(PluginListener listener) {
        synchronized (init_complete_fired_set) {

            if (init_complete_fired_set.contains(listener)) {

                return;
            }

            init_complete_fired_set.add(listener);
        }

        try {
            listener.initializationComplete();
        } catch (Exception e) {
            Debug.out(e);
        }
    }

    protected void closedownInitiated() {
        Iterator it = listeners.iterator();

        while (it.hasNext()) {

            try {
                ((PluginListener) it.next()).closedownInitiated();

            } catch (Throwable e) {

                Debug.printStackTrace(e);
            }
        }

        for (int i = 0; i < children.size(); i++) {

            ((PluginInterfaceImpl) children.get(i)).closedownInitiated();
        }
    }

    protected void closedownComplete() {
        Iterator it = listeners.iterator();

        while (it.hasNext()) {

            try {
                ((PluginListener) it.next()).closedownComplete();

            } catch (Throwable e) {

                Debug.printStackTrace(e);
            }
        }

        for (int i = 0; i < children.size(); i++) {

            ((PluginInterfaceImpl) children.get(i)).closedownComplete();
        }
    }

    public ClassLoader getPluginClassLoader() {
        return (class_loader);
    }

    public PluginInterface getLocalPluginInterface(Class plugin_class, String id)

    throws PluginException {
        try {
            Plugin p = (Plugin) plugin_class.newInstance();

            // Discard plugin.id from the properties, we want the
            // plugin ID we create to take priority - not a value
            // from the original plugin ID properties file.
            Properties local_props = new Properties(props);
            local_props.remove("plugin.id");

            if (id.endsWith("_v")) {

                throw (new Exception("Verified plugins must be loaded from a jar"));
            }

            PluginInterfaceImpl pi =
                    new PluginInterfaceImpl(p, initialiser, initialiser_key, class_loader, null, key + "." + id, local_props, pluginDir,
                            getPluginID() + "." + id, plugin_version);

            initialiser.fireCreated(pi);

            p.initialize(pi);

            children.add(pi);

            return (pi);

        } catch (Throwable e) {

            if (e instanceof PluginException) {

                throw ((PluginException) e);
            }

            throw (new PluginException("Local initialisation fails", e));
        }
    }

    public IPCInterfaceImpl getIPC() {
        return (ipc_interface);
    }

    public boolean isShared() {
        PluginDeprecation.call("isShared", this.given_plugin_id);
        return getPluginState().isShared();
    }

    // Not exposed in the interface.
    void setAsFailed() {
        getPluginState().setDisabled(true);
        state.failed = true;
    }

    protected void destroy() {
        class_loader = null;

        // unhook the reference to the plugin but leave with a valid reference in case
        // something tries to use it

        plugin = new FailedPlugin("Plugin '" + getPluginID() + "' has been unloaded!", null);
    }

    public void addListener(PluginListener l) {
        listeners.add(l);

        if (initialiser.isInitialisationComplete()) {

            fireInitComplete(l);
        }
    }

    public void removeListener(final PluginListener l) {
        listeners.remove(l);

        // we want to remove this ref, but there is a *small* chance that there's a parallel thread firing the complete so
        // decrease chance of hanging onto unwanted ref

        new DelayedEvent("PIL:clear", 10000, new AERunnable() {
            public void runSupport() {
                synchronized (init_complete_fired_set) {

                    init_complete_fired_set.remove(l);
                }
            }
        });
    }

    public void addEventListener(final PluginEventListener l) {
        initialiser.runPEVTask(new AERunnable() {
            public void runSupport() {
                List<PluginEvent> events = initialiser.getPEVHistory();

                for (PluginEvent event : events) {

                    try {
                        l.handleEvent(event);

                    } catch (Throwable e) {

                        Debug.out(e);
                    }
                }
                event_listeners.add(l);
            }
        });
    }

    public void removeEventListener(final PluginEventListener l) {
        initialiser.runPEVTask(new AERunnable() {
            public void runSupport() {
                event_listeners.remove(l);
            }
        });
    }

    public void firePluginEvent(final PluginEvent event) {
        initialiser.runPEVTask(new AERunnable() {
            public void runSupport() {
                firePluginEventSupport(event);
            }
        });
    }

    protected void firePluginEventSupport(PluginEvent event) {
        Iterator<PluginEventListener> it = event_listeners.iterator();

        while (it.hasNext()) {

            try {
                PluginEventListener listener = it.next();

                listener.handleEvent(event);

            } catch (Throwable e) {

                Debug.printStackTrace(e);
            }
        }

        for (int i = 0; i < children.size(); i++) {

            ((PluginInterfaceImpl) children.get(i)).firePluginEvent(event);
        }
    }

    protected void generateEvidence(IndentWriter writer) {
        writer.println(getPluginName());

        try {
            writer.indent();

            writer.println("id:" + getPluginID() + ",version:" + getPluginVersion());

            String user_dir = FileUtil.getUserFile("plugins").toString();
            String shared_dir = FileUtil.getApplicationFile("plugins").toString();

            String plugin_dir = getPluginDirectoryName();

            String type;
            boolean built_in = false;

            if (plugin_dir.startsWith(shared_dir)) {

                type = "shared";

            } else if (plugin_dir.startsWith(user_dir)) {

                type = "per-user";

            } else {

                built_in = true;

                type = "built-in";
            }

            PluginState ps = getPluginState();

            String info = getPluginconfig().getPluginStringParameter("plugin.info");

            writer.println("type:" + type + ",enabled=" + !ps.isDisabled() + ",load_at_start=" + ps.isLoadedAtStartup() + ",operational="
                    + ps.isOperational() + (info == null || info.length() == 0 ? "" : (",info=" + info)));

            if (ps.isOperational()) {

                Plugin plugin = getPlugin();

                if (plugin instanceof AEDiagnosticsEvidenceGenerator) {

                    try {
                        writer.indent();

                        ((AEDiagnosticsEvidenceGenerator) plugin).generate(writer);

                    } catch (Throwable e) {

                        writer.println("Failed to generate plugin-specific info: " + Debug.getNestedExceptionMessage(e));

                    } finally {

                        writer.exdent();
                    }
                }
            } else {
                if (!built_in) {

                    File dir = new File(plugin_dir);

                    if (dir.exists()) {

                        String[] files = dir.list();

                        if (files != null) {

                            String files_str = "";

                            for (String f : files) {

                                files_str += (files_str.length() == 0 ? "" : ", ") + f;
                            }

                            writer.println("    files: " + files_str);
                        }
                    }
                }
            }
        } finally {

            writer.exdent();
        }
    }

    public boolean isDisabled() {
        PluginDeprecation.call("isDisabled", this.given_plugin_id);
        return getPluginState().isDisabled();
    }

    public void setDisabled(boolean disabled) {
        PluginDeprecation.call("setDisabled", this.given_plugin_id);
        getPluginState().setDisabled(disabled);
    }

    public PluginState getPluginState() {
        return this.state;
    }

    PluginStateImpl getPluginStateImpl() {
        return this.state;
    }

    // unfortunately we need to protect ourselves against the plugin itself trying to set
    // plugin.version and plugin.id as this screws things up if they get it "wrong".
    // They should be setting these things in the plugin.properties file
    // currently the RSSImport plugin does this (version 1.1 sets version as 1.0)

    protected class propertyWrapper extends Properties {
        protected boolean initialising = true;

        protected propertyWrapper(Properties _props) {
            Iterator it = _props.keySet().iterator();

            while (it.hasNext()) {

                Object key = it.next();

                put(key, _props.get(key));
            }

            initialising = false;
        }

        public Object setProperty(String str, String val) {
            // if its us then we probably know what we're doing :P

            if (!(plugin.getClass().getName().startsWith("org.gudy") || plugin.getClass().getName().startsWith("com.aelitis."))) {

                if (str.equalsIgnoreCase("plugin.id") || str.equalsIgnoreCase("plugin.version")) {

                    if (org.gudy.azureus2.core3.logging.Logger.isEnabled())
                        org.gudy.azureus2.core3.logging.Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "Plugin '" + getPluginName()
                                + "' tried to set property '" + str + "' - action ignored"));

                    return (null);
                }
            }

            return (super.setProperty(str, val));
        }

        public Object put(Object key, Object value) {
            // if its us then we probably know what we're doing :P

            if (!(plugin.getClass().getName().startsWith("org.gudy") || plugin.getClass().getName().startsWith("com.aelitis."))) {

                if ((!initialising) && key instanceof String) {

                    String k_str = (String) key;

                    if (k_str.equalsIgnoreCase("plugin.id") || k_str.equalsIgnoreCase("plugin.version")) {

                        if (org.gudy.azureus2.core3.logging.Logger.isEnabled())
                            org.gudy.azureus2.core3.logging.Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "Plugin '" + getPluginName()
                                    + "' tried to set property '" + k_str + "' - action ignored"));

                        return (null);
                    }
                }
            }

            return (super.put(key, value));
        }

        public Object get(Object key) {
            return (super.get(key));
        }
    }
}
